Types of Development#

In this notebook, for the “at risk” sites, we will classify what is causing them to be the most at risk, from housing, offices, and industrial.

Hide code cell source
#First recreate the data from the preliminary analysis
import geopandas as gpd
import pandas as pd

# Load and join GMCA housing, industrial and office supply data
housing_supply_gdf = gpd.read_file("data/gmca_data/2024 GM Housing Land Supply GIS.shp")
industrial_supply_gdf = gpd.read_file("data/gmca_data/2024 GM Industrial-warehousing Land Supply GIS.shp")
offices_supply_gdf = gpd.read_file("data/gmca_data/2024 GM Offices Land Supply GIS.shp")
total_supply_gdf = pd.concat(
    [housing_supply_gdf, industrial_supply_gdf, offices_supply_gdf]
)

# Load and tidy GMEU Sites of Biological Importance data
sbi_gdf = gpd.read_file("data/gmeu_data/gm_sbi.shp")
sbi_gdf["Category"] = "Site of Biological Importance"
sbi_gdf = sbi_gdf.rename(columns = {"district": "LAName", "site_nam": "SiteRef"})

# Join GMCA and GMEU data
full_data_gdf = pd.concat(
    [total_supply_gdf, sbi_gdf[["SiteRef", "LAName", "Category", "geometry"]]]
)

#Use geopandas to get centroids of all the sites
full_data_gdf["centroid"] = full_data_gdf.centroid
full_data_gdf["ref"] = range(len(full_data_gdf))

#Split into sites of biological importance and non-biological importance
sbi = full_data_gdf[full_data_gdf["Category"] == "Site of Biological Importance"]
non_sbi = full_data_gdf[full_data_gdf["Category"] != "Site of Biological Importance"]

#Find the number of new developments less than 1km away for each SBI
sbinames = list(sbi["SiteRef"]) #list of all the sbis
indexes = list(sbi["ref"])

distances = list()
less_than_1km = list() #creating empty lists to add to data frame

for x in sbi["centroid"]: #loop through each sbi
    y = non_sbi["centroid"].distance(x) #find all the distances of developments to centroid
    for distance in y: #filter for less than 1km away
            if distance <1000:
                distances.append(distance)
    r = len(distances)    #find no. developments less than 1km away to each sbi
    less_than_1km.append(r)
    distances = list()

Dev_1km = pd.DataFrame({'SiteRef':sbinames, 'No. Sites in 1km': less_than_1km, 'ref': indexes}) #create dataframe of sbi and no. developments     

Dev_1km
SiteRef No. Sites in 1km ref
0 Big Wood 0 4357
1 Winstanley Hall Woods 1 4358
2 Ackhurst Lane Sand Workings 3 4359
3 Abbey Lakes 6 4360
4 Wetland by M6 1 4361
... ... ... ...
531 Mill Race & Pasture at Haughton Dale 8 4888
532 Three Sisters 2 4889
533 Nan Nook Wood 7 4890
534 Big Wood 10 4891
535 Bank Wood & Marsh 11 4892

536 rows × 3 columns

Of the sites at risk, what type of development is posing the most risk?#

First remember what we found from the mapping sites at risk notebook, which was 45 SBI sites with 15 or more proposed developments within a 1km radius.

Dev_1km = Dev_1km[Dev_1km["No. Sites in 1km"] >= 15]

len(Dev_1km)
45

On a map this looks like:

Dev_1km = pd.merge(sbi, Dev_1km, on="ref")

Dev_1km.explore( tiles="CartoDB positron")
Make this Notebook Trusted to load map: File -> Trust Notebook

To find which sites are posing the most risk, repeat the steps to find how many sites are within 1km, but this time using separated datasets for each type of development.

#Filter data for each type of development from the full data which includes the centroid column.
Housing = full_data_gdf[full_data_gdf["Category"] == 'Housing']
Industrial = full_data_gdf[full_data_gdf["Category"] == 'Industrial/warehousing']
Offices = full_data_gdf[full_data_gdf["Category"] == 'Offices']

print(len(Housing) + len(Industrial) + len(Offices))
print(len(non_sbi))
4357
4357
sum(Dev_1km["No. Sites in 1km"])
929

Also, it is useful to note that there are 929 total developments that threaten our “at risk” locations. We can keep this in mind as a baseline for our further calculations.

Housing Risk#

#Find the number of new housing developments less than 1km away for each SBI
sbinames = list(Dev_1km["SiteRef_x"]) #list of all the sbis
indexes = list(Dev_1km["ref"])

distances = list()
less_than_1km = list() #creating empty lists to add to data frame

for x in Dev_1km["centroid"]: #loop through each sbi
    y = Housing["centroid"].distance(x) #find all the distances of developments to centroid
    for distance in y: #filter for less than 1km away
            if distance <1000:
                distances.append(distance)
    r = len(distances)    #find no. developments less than 1km away to each sbi
    less_than_1km.append(r)
    distances = list()

Housing_1km = pd.DataFrame({'SiteRef_x':sbinames, 'No. Sites in 1km': less_than_1km, 'ref': indexes}) #create dataframe of sbi and no. developments     

print("There are " + str(sum(Housing_1km["No. Sites in 1km"])) + " new housing developments affecting the at risk sites.")
There are 807 new housing developments affecting the at risk sites.

Industrial Risk#

#Find the number of new industrial developments less than 1km away for each SBI
sbinames = list(Dev_1km["SiteRef_x"]) #list of all the sbis
indexes = list(Dev_1km["ref"])

distances = list()
less_than_1km = list() #creating empty lists to add to data frame

for x in Dev_1km["centroid"]: #loop through each sbi
    y = Industrial["centroid"].distance(x) #find all the distances of developments to centroid
    for distance in y: #filter for less than 1km away
            if distance <1000:
                distances.append(distance)
    r = len(distances)    #find no. developments less than 1km away to each sbi
    less_than_1km.append(r)
    distances = list()

Industrial_1km = pd.DataFrame({'SiteRef_x':sbinames, 'No. Sites in 1km': less_than_1km, 'ref': indexes}) #create dataframe of sbi and no. developments     

print("There are " + str(sum(Industrial_1km["No. Sites in 1km"])) + " new industrial/warehouse developments affecting the at risk sites.")
There are 71 new industrial/warehouse developments affecting the at risk sites.

Offices Risk#

#Find the number of new office developments less than 1km away for each SBI
sbinames = list(Dev_1km["SiteRef_x"]) #list of all the sbis
indexes = list(Dev_1km["ref"])

distances = list()
less_than_1km = list() #creating empty lists to add to data frame

for x in Dev_1km["centroid"]: #loop through each sbi
    y = Offices["centroid"].distance(x) #find all the distances of developments to centroid
    for distance in y: #filter for less than 1km away
            if distance <1000:
                distances.append(distance)
    r = len(distances)    #find no. developments less than 1km away to each sbi
    less_than_1km.append(r)
    distances = list()

Offices_1km = pd.DataFrame({'SiteRef_x':sbinames, 'No. Sites in 1km': less_than_1km, 'ref': indexes}) #create dataframe of sbi and no. developments     

print("There are " + str(sum(Offices_1km["No. Sites in 1km"])) + " new office developments affecting the at risk sites.")
There are 51 new office developments affecting the at risk sites.

Conclusion#

Above, we have found that there are 807 housing developments, 71 industrial developments and 51 office developments that are affecting our “at risk” sites.

Relevant to the way we calculate the “at risk” which is the number of sites within 1km of the sites of biological importance, this makes sense, as housing developments are generally much smaller, and much more frequent (consider the original map). Therefore there is a higher chance for them to be near an SBI site, and many housing developments can fit within 1km.

It also makes sense that Industrial developments cause slightly more risk than office developments, as they often are found on the outskirts of the city, and are therefore more likely to be closer to sites of biological importance.

full_data_gdf.explore("Category", cmap="tab10", tiles="CartoDB positron")
Make this Notebook Trusted to load map: File -> Trust Notebook